/*********************************************************************************************************************
 * CYT4BB Opensourec Library 即（ CYT4BB 开源库）是一个基于官方 SDK
 *接口的第三方开源库 Copyright (c) 2022 SEEKFREE 逐飞科技
 *
 * 本文件是 CYT4BB 开源库的一部分
 *
 * CYT4BB 开源库 是免费软件
 * 您可以根据自由软件基金会发布的 GPL（GNU General Public License，即
 *GNU通用公共许可证）的条款 即 GPL 的第3版（即
 *GPL3.0）或（您选择的）任何后来的版本，重新发布和/或修改它
 *
 * 本开源库的发布是希望它能发挥作用，但并未对其作任何的保证
 * 甚至没有隐含的适销性或适合特定用途的保证
 * 更多细节请参见 GPL
 *
 * 您应该在收到本开源库的同时收到一份 GPL 的副本
 * 如果没有，请参阅<https://www.gnu.org/licenses/>
 *
 * 额外注明：
 * 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本
 * 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt
 *文件中 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件
 * 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明（即本声明）
 *
 * 文件名称          zf_common_fifo
 * 公司名称          成都逐飞科技有限公司
 * 版本信息          查看 libraries/doc 文件夹内 version 文件 版本说明
 * 开发环境          IAR 9.40.1
 * 适用平台          CYT4BB
 * 店铺链接          https://seekfree.taobao.com/
 *
 * 修改记录
 * 日期              作者                备注
 * 2024-1-4       pudding            first version
 ********************************************************************************************************************/

#include "zf_common_fifo.h"
#include "zf_common_debug.h"

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     FIFO 头指针位移
// 参数说明     *fifo               FIFO 对象指针
// 参数说明     offset              偏移量
// 返回参数     void
// 使用示例     fifo_head_offset(fifo, 1);
// 备注信息     本函数在文件内部调用 用户不用关注 也不可修改
//-------------------------------------------------------------------------------------------------------------------
static void fifo_head_offset(fifo_struct *fifo, uint32 offset) {
  fifo->head += offset;

  while (fifo->max <=
         fifo->head) // 如果范围超过则减缓冲区大小 直到小于最大缓冲区大小
  {
    fifo->head -= fifo->max;
  }
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     FIFO 尾指针位移
// 参数说明     *fifo               FIFO 对象指针
// 参数说明     offset              偏移量
// 返回参数     void
// 使用示例     fifo_end_offset(fifo, 1);
// 备注信息     本函数在文件内部调用 用户不用关注 也不可修改
//-------------------------------------------------------------------------------------------------------------------
static void fifo_end_offset(fifo_struct *fifo, uint32 offset) {
  fifo->end += offset;

  while (fifo->max <=
         fifo->end) // 如果范围超过则减缓冲区大小 直到小于最大缓冲区大小
  {
    fifo->end -= fifo->max;
  }
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     FIFO 重置缓冲器
// 参数说明     *fifo               FIFO 对象指针
// 返回参数     void
// 使用示例     fifo_clear(fifo);
// 备注信息     清空当前 FIFO 对象的内存
//-------------------------------------------------------------------------------------------------------------------
fifo_state_enum fifo_clear(fifo_struct *fifo) {
  zf_assert(NULL != fifo);
  if (fifo->init_state != true)
    // 没初始化过的fifo，直接返回不清空操作
    return FIFO_CLEAR_UNDO;
  fifo_state_enum return_state = FIFO_SUCCESS; // 操作结果初值
  do {
    fifo->execution |= FIFO_RESET; // 重置操作置位
    fifo->head = 0;                // 重置 FIFO 所有数值复位
    fifo->pre_head = 0;            // 清除这个状态位
    fifo->end = 0;                 // 重置 FIFO 所有数值复位
    fifo->size = fifo->max;        // 重置 FIFO 所有数值复位
    switch (fifo->type) {
    case FIFO_DATA_8BIT:
      memset(fifo->buffer, 0, fifo->max);
      break;
    case FIFO_DATA_16BIT:
      memset(fifo->buffer, 0, fifo->max * 2);
      break;
    case FIFO_DATA_32BIT:
      memset(fifo->buffer, 0, fifo->max * 4);
      break;
    }
    fifo->execution = FIFO_IDLE; // 操作状态复位
  } while (0);
  return return_state;
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     FIFO 查询当前数据个数
// 参数说明     *fifo               FIFO 对象指针
// 返回参数     uint32              已使用长度
// 使用示例     uint32 len = fifo_used(fifo);
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
uint32 fifo_used(fifo_struct *fifo) {
  zf_assert(fifo != NULL);
  return (fifo->max - fifo->size); // 返回当前 FIFO 缓冲区中数据个数
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     向 FIFO 中写入数据
// 参数说明     *fifo               FIFO 对象指针
// 参数说明     dat                 数据
// 返回参数     fifo_state_enum     操作状态
// 使用示例     zf_log(fifo_write_element(&fifo, data) == FIFO_SUCCESS,
// "fifo_write_byte error"); 备注信息
//-------------------------------------------------------------------------------------------------------------------
fifo_state_enum fifo_write_element(fifo_struct *fifo, uint32 dat) {
  zf_assert(NULL != fifo);
  fifo_state_enum return_state = FIFO_SUCCESS; // 操作结果初值

  do {
    if ((FIFO_RESET | FIFO_WRITE) &
        fifo->execution) // 不在写入与重置状态 避免写入竞争与指向错误
    {
      return_state = FIFO_WRITE_UNDO; // 写入操作未完成
      break;
    }
    fifo->execution |= FIFO_WRITE; // 写入操作置位

    if (1 <= fifo->size) // 剩余空间足够装下本次数据
    {
      switch (fifo->type) {
      case FIFO_DATA_8BIT:
        ((uint8 *)fifo->buffer)[fifo->head] = (uint8)dat;
        break;
      case FIFO_DATA_16BIT:
        ((uint16 *)fifo->buffer)[fifo->head] = (uint16)dat;
        break;
      case FIFO_DATA_32BIT:
        ((uint32 *)fifo->buffer)[fifo->head] = dat;
        break;
      }
      fifo_head_offset(fifo, 1); // 头指针偏移
      fifo->size -= 1;           // 缓冲区剩余长度减小
    } else {
      return_state = FIFO_SPACE_NO_ENOUGH; // 当前 FIFO 缓冲区满 不能再写入数据
                                           // 返回空间不足
    }
    fifo->execution &= ~FIFO_WRITE; // 写入操作复位
  } while (0);

  return return_state;
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     向 FIFO 中写入数据
// 参数说明     *fifo               FIFO 对象指针
// 参数说明     *dat                数据来源缓冲区指针
// 参数说明     length              需要写入的数据长度
// 返回参数     fifo_state_enum     操作状态
// 使用示例     zf_log(fifo_write_buffer(&fifo, data, 32) == FIFO_SUCCESS,
// "fifo_write_buffer error"); 备注信息
//-------------------------------------------------------------------------------------------------------------------
fifo_state_enum fifo_write_buffer(fifo_struct *fifo, void *dat, uint32 length) {
  zf_assert(NULL != fifo);
  fifo_state_enum return_state = FIFO_SUCCESS; // 操作结果初值
  uint32 temp_length = 0;

  do {
    if (NULL == dat) {
      return_state = FIFO_BUFFER_NULL; // 用户缓冲区异常
      break;
    }
    if ((FIFO_RESET | FIFO_WRITE) &
        fifo->execution) // 不在写入与重置状态 避免写入竞争与指向错误
    {
      return_state = FIFO_WRITE_UNDO; // 写入操作未完成
      break;
    }
    fifo->execution |= FIFO_WRITE; // 写入操作置位

    if (length <= fifo->size) // 剩余空间足够装下本次数据
    {
      temp_length =
          fifo->max - fifo->head; // 计算头指针距离缓冲区尾还有多少空间

      if (length >
          temp_length) // 距离缓冲区尾长度不足写入数据 环形缓冲区分段操作
      {
        switch (fifo->type) {
        case FIFO_DATA_8BIT: {
          memcpy(&(((uint8 *)fifo->buffer)[fifo->head]), dat,
                 temp_length);                 // 拷贝第一段数据
          fifo_head_offset(fifo, temp_length); // 头指针偏移
          memcpy(&(((uint8 *)fifo->buffer)[fifo->head]),
                 &(((uint8 *)dat)[temp_length]),
                 length - temp_length);                 // 拷贝第二段数据
          fifo_head_offset(fifo, length - temp_length); // 头指针偏移
        } break;
        case FIFO_DATA_16BIT: {
          memcpy(&(((uint16 *)fifo->buffer)[fifo->head]), dat,
                 temp_length * 2);             // 拷贝第一段数据
          fifo_head_offset(fifo, temp_length); // 头指针偏移
          memcpy(&(((uint16 *)fifo->buffer)[fifo->head]),
                 &(((uint16 *)dat)[temp_length]),
                 (length - temp_length) * 2);           // 拷贝第二段数据
          fifo_head_offset(fifo, length - temp_length); // 头指针偏移
        } break;
        case FIFO_DATA_32BIT: {
          memcpy(&(((uint32 *)fifo->buffer)[fifo->head]), dat,
                 temp_length * 4);             // 拷贝第一段数据
          fifo_head_offset(fifo, temp_length); // 头指针偏移
          memcpy(&(((uint32 *)fifo->buffer)[fifo->head]),
                 &(((uint32 *)dat)[temp_length]),
                 (length - temp_length) * 4);           // 拷贝第二段数据
          fifo_head_offset(fifo, length - temp_length); // 头指针偏移
        } break;
        }
      } else {
        switch (fifo->type) {
        case FIFO_DATA_8BIT: {
          memcpy(&(((uint8 *)fifo->buffer)[fifo->head]), dat,
                 length);                 // 一次完整写入
          fifo_head_offset(fifo, length); // 头指针偏移
        } break;
        case FIFO_DATA_16BIT: {
          memcpy(&(((uint16 *)fifo->buffer)[fifo->head]), dat,
                 length * 2);             // 一次完整写入
          fifo_head_offset(fifo, length); // 头指针偏移
        } break;
        case FIFO_DATA_32BIT: {
          memcpy(&(((uint32 *)fifo->buffer)[fifo->head]), dat,
                 length * 4);             // 一次完整写入
          fifo_head_offset(fifo, length); // 头指针偏移
        } break;
        }
      }

      fifo->size -= length; // 缓冲区剩余长度减小
    } else {
      return_state = FIFO_SPACE_NO_ENOUGH; // 当前 FIFO 缓冲区满 不能再写入数据
                                           // 返回空间不足
    }
    fifo->execution &= ~FIFO_WRITE; // 写入操作复位
  } while (0);

  return return_state;
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     从 FIFO 读取数据
// 参数说明     *fifo               FIFO 对象指针
// 参数说明     *dat                目标缓冲区指针
// 参数说明     flag                是否变更 FIFO 状态 可选择是否清空读取的数据
// 返回参数     fifo_state_enum     操作状态
// 使用示例     zf_log(fifo_read_element(&fifo, data, FIFO_READ_ONLY) ==
// FIFO_SUCCESS, "fifo_read_byte error"); 备注信息
//-------------------------------------------------------------------------------------------------------------------
fifo_state_enum fifo_read_element(fifo_struct *fifo, void *dat,
                                  fifo_operation_enum flag) {
  zf_assert(NULL != fifo);
  fifo_state_enum return_state = FIFO_SUCCESS; // 操作结果初值

  do {
    if (NULL == dat) {
      return_state = FIFO_BUFFER_NULL; // 用户缓冲区异常
    } else {
      if ((FIFO_RESET | FIFO_CLEAR) &
          fifo->execution) // 判断是否当前 FIFO 是否在执行清空或重置操作
      {
        return_state = FIFO_READ_UNDO; // 读取操作未完成
        break;
      }

      if (1 > fifo_used(fifo)) {
        return_state = FIFO_DATA_NO_ENOUGH; // 缓冲区没有数据 返回数据长度不足
        break;                              // 直接退出操作
      }

      fifo->execution |= FIFO_READ; // 读操作置位
      switch (fifo->type) {
      case FIFO_DATA_8BIT:
        *((uint8 *)dat) = ((uint8 *)fifo->buffer)[fifo->end];
        break;
      case FIFO_DATA_16BIT:
        *((uint16 *)dat) = ((uint16 *)fifo->buffer)[fifo->end];
        break;
      case FIFO_DATA_32BIT:
        *((uint32 *)dat) = ((uint32 *)fifo->buffer)[fifo->end];
        break;
      }
      fifo->execution &= ~FIFO_READ; // 读操作复位
    }

    if (FIFO_READ_AND_CLEAN == flag) // 如果选择读取并更改 FIFO 状态
    {
      if ((FIFO_RESET | FIFO_CLEAR | FIFO_READ) ==
          fifo->execution) // 不在 重置 清空 读取 状态 避免异常
      {
        return_state = FIFO_CLEAR_UNDO; // 清空操作未完成
        break;
      }
      fifo->execution |= FIFO_CLEAR;  // 清空作置位
      fifo_end_offset(fifo, 1);       // 移动 FIFO 头指针
      fifo->size += 1;                // 释放对应长度空间
      fifo->execution &= ~FIFO_CLEAR; // 清空作复位
    }
  } while (0);

  return return_state;
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     从 FIFO 读取数据
// 参数说明     *fifo               FIFO 对象指针
// 参数说明     *dat                目标缓冲区指针
// 参数说明     *length             读取的数据长度
// 如果没有这么多数据这里会被修改 参数说明     flag                是否变更 FIFO
// 状态 可选择是否清空读取的数据 返回参数     fifo_state_enum     操作状态
// 使用示例     zf_log(fifo_read_buffer(&fifo, data, &length, FIFO_READ_ONLY) ==
// FIFO_SUCCESS, "fifo_read_buffer error"); 备注信息
//-------------------------------------------------------------------------------------------------------------------
fifo_state_enum fifo_read_buffer(fifo_struct *fifo, void *dat, uint32 *length,
                                 fifo_operation_enum flag) {
  zf_assert(NULL != fifo);
  zf_assert(NULL != length);
  fifo_state_enum return_state = FIFO_SUCCESS; // 操作结果初值
  uint32 temp_length = 0;
  uint32 fifo_data_length = 0;

  do {
    if (NULL == dat) {
      return_state = FIFO_BUFFER_NULL;
    } else {
      if ((FIFO_RESET | FIFO_CLEAR) &
          fifo->execution) // 判断是否当前 FIFO 是否在执行清空或重置操作
      {
        *length = fifo_data_length;    // 纠正读取的长度
        return_state = FIFO_READ_UNDO; // 读取操作未完成
        break;
      }

      fifo_data_length = fifo_used(fifo); // 获取当前数据有多少
      if (*length > fifo_data_length)     // 判断长度是否足够
      {
        *length = fifo_data_length;         // 纠正读取的长度
        return_state = FIFO_DATA_NO_ENOUGH; // 标志数据不够
        if (0 == fifo_data_length) // 如果没有数据 就直接退出
        {
          fifo->execution &= ~FIFO_READ; // 读操作复位
          break;
        }
      }

      fifo->execution |= FIFO_READ; // 读操作置位
      temp_length = fifo->max - fifo->end; // 计算尾指针距离缓冲区尾还有多少空间
      if (*length <= temp_length) // 足够一次性读取完毕
      {
        switch (fifo->type) {
        case FIFO_DATA_8BIT:
          memcpy(dat, &(((uint8 *)fifo->buffer)[fifo->end]), *length);
          break;
        case FIFO_DATA_16BIT:
          memcpy(dat, &(((uint16 *)fifo->buffer)[fifo->end]), *length * 2);
          break;
        case FIFO_DATA_32BIT:
          memcpy(dat, &(((uint32 *)fifo->buffer)[fifo->end]), *length * 4);
          break;
        }
      } else {
        switch (fifo->type) {
        case FIFO_DATA_8BIT: {
          memcpy(dat, &(((uint8 *)fifo->buffer)[fifo->end]), temp_length);
          memcpy(&(((uint8 *)dat)[temp_length]), fifo->buffer,
                 *length - temp_length);
        } break;
        case FIFO_DATA_16BIT: {
          memcpy(dat, &(((uint16 *)fifo->buffer)[fifo->end]), temp_length * 2);
          memcpy(&(((uint16 *)dat)[temp_length]), fifo->buffer,
                 (*length - temp_length) * 2);
        } break;
        case FIFO_DATA_32BIT: {
          memcpy(dat, &(((uint32 *)fifo->buffer)[fifo->end]), temp_length * 4);
          memcpy(&(((uint32 *)dat)[temp_length]), fifo->buffer,
                 (*length - temp_length) * 4);
        } break;
        }
      }
      fifo->execution &= ~FIFO_READ; // 读操作复位
    }

    if (FIFO_READ_AND_CLEAN == flag) // 如果选择读取并更改 FIFO 状态
    {
      if ((FIFO_RESET | FIFO_CLEAR | FIFO_READ) ==
          fifo->execution) // 不在 重置 清空 读取 状态 避免异常
      {
        return_state = FIFO_CLEAR_UNDO; // 清空操作未完成
        break;
      }
      fifo->execution |= FIFO_CLEAR;  // 清空作置位
      fifo_end_offset(fifo, *length); // 移动 FIFO 头指针
      fifo->size += *length;          // 释放对应长度空间
      fifo->execution &= ~FIFO_CLEAR; // 清空作复位
    }
  } while (0);

  return return_state;
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     从 FIFO 尾部读取指定长度 buffer
// 参数说明     *fifo               FIFO 对象指针
// 参数说明     *dat                目标缓冲区指针
// 参数说明     *length             读取的数据长度
// 如果没有这么多数据这里会被修改 参数说明     flag                是否变更 FIFO
// 状态 可选择是否清空读取的数据 返回参数     fifo_state_enum     操作状态
// 使用示例     zf_log(fifo_read_tail_buffer(&fifo, data, &length,
// FIFO_READ_ONLY) == FIFO_SUCCESS, "fifo_read_buffer error"); 备注信息 如果使用
// FIFO_READ_AND_CLEAN 操作 将会丢弃所有数据并清空整个 FIFO
//              如果使用 FIFO_READ_AND_CLEAN 操作 将会丢弃所有数据并清空整个
//              FIFO 如果使用 FIFO_READ_AND_CLEAN 操作
//              将会丢弃所有数据并清空整个 FIFO
//-------------------------------------------------------------------------------------------------------------------
fifo_state_enum fifo_read_tail_buffer(fifo_struct *fifo, void *dat,
                                      uint32 *length,
                                      fifo_operation_enum flag) {
  zf_assert(NULL != fifo);
  zf_assert(NULL != length);
  fifo_state_enum return_state = FIFO_SUCCESS; // 操作结果初值
  uint32 temp_length = 0;
  uint32 fifo_data_length = 0;

  do {
    if (NULL == dat) {
      return_state = FIFO_BUFFER_NULL;
    } else {
      if ((FIFO_RESET | FIFO_CLEAR | FIFO_WRITE) &
          fifo->execution) // 判断是否当前 FIFO 是否在执行清空或重置操作
      {
        *length = fifo_data_length;    // 纠正读取的长度
        return_state = FIFO_READ_UNDO; // 读取操作未完成
        break;
      }

      fifo_data_length = fifo_used(fifo); // 获取当前数据有多少
      if (*length > fifo_data_length)     // 判断长度是否足够
      {
        *length = fifo_data_length;         // 纠正读取的长度
        return_state = FIFO_DATA_NO_ENOUGH; // 标志数据不够
        if (0 == fifo_data_length) // 如果没有数据 就直接退出
        {
          fifo->execution &= ~FIFO_READ; // 读操作复位
          break;
        }
      }

      fifo->execution |= FIFO_READ; // 读操作置位
      if ((fifo->head > fifo->end) || (fifo->head >= *length)) {
        switch (fifo->type) {
        case FIFO_DATA_8BIT:
          memcpy(dat, &(((uint8 *)fifo->buffer)[fifo->head - *length]),
                 *length);
          break;
        case FIFO_DATA_16BIT:
          memcpy(dat, &(((uint16 *)fifo->buffer)[fifo->head - *length]),
                 *length * 2);
          break;
        case FIFO_DATA_32BIT:
          memcpy(dat, &(((uint32 *)fifo->buffer)[fifo->head - *length]),
                 *length * 4);
          break;
        }
      } else {
        temp_length =
            *length - fifo->head; // 计算尾指针距离缓冲区尾还有多少空间
        switch (fifo->type) {
        case FIFO_DATA_8BIT: {
          memcpy(dat, &(((uint8 *)fifo->buffer)[fifo->max - temp_length]),
                 temp_length);
          memcpy(&(((uint8 *)dat)[temp_length]),
                 &(((uint8 *)fifo->buffer)[fifo->head - *length]),
                 (*length - temp_length));
        } break;
        case FIFO_DATA_16BIT: {
          memcpy(dat, &(((uint16 *)fifo->buffer)[fifo->max - temp_length]),
                 temp_length * 2);
          memcpy(&(((uint16 *)dat)[temp_length]),
                 &(((uint16 *)fifo->buffer)[fifo->head - *length]),
                 (*length - temp_length) * 2);
        } break;
        case FIFO_DATA_32BIT: {
          memcpy(dat, &(((uint32 *)fifo->buffer)[fifo->max - temp_length]),
                 temp_length * 4);
          memcpy(&(((uint32 *)dat)[temp_length]),
                 &(((uint32 *)fifo->buffer)[fifo->head - *length]),
                 (*length - temp_length) * 4);
        } break;
        }
      }
      fifo->execution &= ~FIFO_READ; // 读操作复位
    }

    if (FIFO_READ_AND_CLEAN == flag) // 如果选择读取并更改 FIFO 状态
    {
      if ((FIFO_RESET | FIFO_CLEAR | FIFO_READ) ==
          fifo->execution) // 不在 重置 清空 读取 状态 避免异常
      {
        return_state = FIFO_CLEAR_UNDO; // 清空操作未完成
        break;
      }
      fifo_clear(fifo);
    }
  } while (0);

  return return_state;
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     FIFO 初始化 挂载对应缓冲区
// 参数说明     *fifo               FIFO 对象指针
// 参数说明     type                FIFO 数据位数
// 参数说明     *buffer_addr        要挂载的缓冲区
// 参数说明     size                缓冲区大小
// 返回参数     fifo_state_enum     操作状态
// 使用示例     fifo_init(&user_fifo, user_buffer, 64);
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
fifo_state_enum fifo_init(fifo_struct *fifo, fifo_data_type_enum type,
                          void *buffer_addr, uint32 size) {
  zf_assert(NULL != fifo);
  fifo_state_enum return_state = FIFO_SUCCESS;
  do {
    fifo->buffer = buffer_addr;
    fifo->execution = FIFO_IDLE;
    fifo->type = type;
    fifo->head = 0;
    fifo->end = 0;
    fifo->size = size;
    fifo->max = size;
  } while (0);
  fifo->init_state = true;
  return return_state;
}